/*
** Copyright (C) 2009 Joshua Brent Marsh <joshua@icub3d.com>
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 3 of the License, or
** (at your option) any later version.
**  
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**  
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**  
*/

/* $Id: test_tree.c 32 2009-10-28 22:51:19Z joshua@icub3d.com $ */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <malloc.h>

#include <CUnit/Basic.h>

#include <../src/tree.h>
#include <../src/function_prototypes.h>

#include "test_helpers.h"
#include "test_tree.h"

TreeNode *nodes[4];
TreeNode *rchild[4];

int
init_test_tree_suite ()
{
  return 0;
}

int
clean_test_tree_suite ()
{
  return 0;
}

void
test_tree_node_create ()
{
  size_t x, y;
  int *data;
  TreeNode *child[4];

  for (x = 0; x < 4; x++)
    {
      for (y = 0; y < 4; y++)
	{
	  data = create_int (y);
	  child[y] = tree_node_create (NULL, data, 0);
	  CU_ASSERT (child[y] != NULL);
	}

      data = create_int (x);
      nodes[x] = tree_node_create (NULL, data, 4, child[0], child[1], 
				   child[2], child[3]);

      CU_ASSERT (nodes[x] != NULL);
      CU_ASSERT (list_size (tree_node_children (nodes[x])) == 4);
    }

}

void
test_tree_node_add_child ()
{
  size_t x, y;
  int *data;
  TreeNode *child;

  for (x = 0; x < 4; x++)
    {
      for (y = 4; y < 8; y++)
	{
	  data = create_int (y);
	  child = tree_node_create (NULL, data, 0);
	  CU_ASSERT (tree_node_add_child (nodes[x], child) == 1);

	  if (y == 7)
	    rchild[x] = child;
	}

      CU_ASSERT (list_size (tree_node_children (nodes[x])) == 8);
    }

  tree_node_add_child (nodes[1], nodes[2]);
  tree_node_add_child (nodes[2], nodes[3]);

}

void
test_tree_node_remove_child ()
{
  size_t x;
  for (x = 0; x < 4; x++)
    {
      CU_ASSERT (tree_node_remove_child (nodes[x], 
					 rchild[(x == 4 ? 0 : x + 1)])
		 == 0);
      CU_ASSERT (tree_node_remove_child (nodes[x], rchild[x])
		 == 1);

      tree_node_destroy (rchild[x], destroy_int, 0);
    }  
}

void
test_tree_node_children ()
{
  size_t x;
  for (x = 0; x < 4; x++)
    CU_ASSERT (tree_node_children (nodes[x]) == nodes[x]->children);
}

void
test_tree_node_clear_children ()
{
  List *children;
  TreeNode *childrens[7];
  size_t x;

  children = tree_node_children (nodes[3]);
  for (x = 0; x < 7; x++)
    childrens[x] = list_get (children, x);

  tree_node_clear_children (nodes[3]);
  CU_ASSERT (list_size (children) == 0);

  for (x = 0; x < 7; x++)
    tree_node_add_child (nodes[3], childrens[x]);
}

void
test_tree_node_find_root ()
{
  CU_ASSERT (tree_node_find_root (nodes[0]) == nodes[0]);
  CU_ASSERT (tree_node_find_root (nodes[1]) == nodes[1]);
  CU_ASSERT (tree_node_find_root (nodes[2]) == nodes[1]);
  CU_ASSERT (tree_node_find_root (nodes[3]) == nodes[1]);
}

void
test_tree_node_height ()
{
  CU_ASSERT (tree_node_height (nodes[0]) == 2);
  CU_ASSERT (tree_node_height (nodes[1]) == 4);
  CU_ASSERT (tree_node_height (nodes[2]) == 3);
  CU_ASSERT (tree_node_height (nodes[3]) == 2);
}

void
test_tree_node_depth ()
{
  CU_ASSERT (tree_node_depth (nodes[0]) == 0);
  CU_ASSERT (tree_node_depth (nodes[1]) == 0);
  CU_ASSERT (tree_node_depth (nodes[2]) == 1);
  CU_ASSERT (tree_node_depth (nodes[3]) == 2);
}

void
test_tree_node_descendants ()
{
  CU_ASSERT (tree_node_descendants (nodes[0]) == 7);
  CU_ASSERT (tree_node_descendants (nodes[1]) == 23);
  CU_ASSERT (tree_node_descendants (nodes[2]) == 15);
  CU_ASSERT (tree_node_descendants (nodes[3]) == 7);
}

void
test_tree_node_destroy ()
{
  tree_node_destroy (nodes[0], destroy_int, 1);
  tree_node_destroy (nodes[1], destroy_int, 1);
}

int
make_tree_suite (CU_pSuite s)
{
  s = CU_add_suite ("Test Tree Suite", 
		    init_test_tree_suite, 
		    clean_test_tree_suite);
  if (s == NULL)
    {
      return CU_get_error();
    }

  if (
      CU_add_test (s, "test_tree_node_create", test_tree_node_create) == NULL ||
      CU_add_test (s, "test_tree_node_add_child", 
		   test_tree_node_add_child) == NULL ||
      CU_add_test (s, "test_tree_node_remove_child", 
		   test_tree_node_remove_child) == NULL ||
      CU_add_test (s, "test_tree_node_children", 
		   test_tree_node_children) == NULL ||
      CU_add_test (s, "test_tree_node_clear_children", 
		   test_tree_node_clear_children) == NULL ||
      CU_add_test (s, "test_tree_node_find_root", 
		   test_tree_node_find_root) == NULL ||
      CU_add_test (s, "test_tree_node_height", test_tree_node_height) == NULL ||
      CU_add_test (s, "test_tree_node_depth",
		   test_tree_node_depth) == NULL ||
      CU_add_test (s, "test_tree_node_descendants",
		   test_tree_node_descendants) == NULL ||
      CU_add_test (s, "test_tree_node_destroy",
		   test_tree_node_destroy) == NULL)
    {
      return CU_get_error();
    }

  return CU_get_error();
}



